// $codepro.audit.disable largeNumberOfParameters, com.instantiations.assist.eclipse.callNextWithoutHasNext, nullPointerDereference, reusableImmutables, spellCheckComments, spellCheckIdentifiers, spellCheckStringLiterals, variableUsage
/**
 * Package domain
 */
package teamrocket.domain; // $codepro.audit.disable packagePrefixNamingConvention

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.Collection;
import java.util.ArrayList;
import java.util.List;

import teamrocket.db.DBWrapper;
import teamrocket.logging.TLogger;

/**
 * Represents a patient in the database
 * @author Stephen
 *
 * @version $Revision: 1.0 $
 */
public class Patient extends User{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * Field accessLevel.
	 */
	private String accessLevel;
	
	/**
	 * Field patientInformation.
	 */
	private PatientInformation patientInformation;
	
	/**
	 * Field treatmentRecord.
	 */
	private Collection<TreatmentRecord> treatmentRecord;
	
	/**
	 * Field appointments.
	 */
	private Collection<Appointment> appointments;
	
	/**
	 * Field totalNumOfVisits.
	 */
	private int totalNumOfVisits;
	
	/**
	 * Field totalPaymentinMonth.
	 */
	private float totalPaymentinMonth;
	
	/**
	 * Field patientid.
	 */
	private int patientid;
	
	/**
	 * Field PATIENTDEFPERMS.
	 * (value is "User.LOGIN + User.REQAPPT + User.VIEWMHIST")
	 */
	public static final String PATIENTDEFPERMS = 
		User.LOGIN + User.REQAPPT + User.VIEWMHIST;
	
	/**
	 * Constructs a patient object in memory
	 * @param accessLevel
	 * @param patientInformation
	 * @param username
	 * @param password
	 * @param firstName
	 * @param lastName
	 */
	public Patient(String accessLevel, PatientInformation patientInformation,
			String username, String password, String firstName, String lastName) {
		super(username, password, firstName, lastName, "p", PATIENTDEFPERMS);
		this.accessLevel = accessLevel;
		this.patientInformation = patientInformation;
		this.treatmentRecord = new ArrayList<TreatmentRecord>();
		this.appointments = new ArrayList<Appointment>();
		this.totalNumOfVisits = 0;
		this.totalPaymentinMonth = 0;
		TLogger.getInstance().getLogger().log(Level.INFO,
				"Creating new Patient named " + username);
	}
	
	/**
	 * Method getAccessLevel.
	 * @return String
	 */
	public String getAccessLevel() {
		return accessLevel;
	}
	
	/**
	 * Method setAccessLevel.
	 * @param accessLevel String
	 */
	public void setAccessLevel(String accessLevel) {
		this.accessLevel = accessLevel;
	}
	
	/**
	 * Method getPatientInformation.
	 * @return PatientInformation
	 */
	public PatientInformation getPatientInformation() {
		return patientInformation;
	}
	
	/**
	 * Method setPatientInformation.
	 * @param patientInformation PatientInformation
	 */
	public void setPatientInformation(PatientInformation patientInformation) {
		this.patientInformation = patientInformation;
	}
	
	/**
	 * Method getTreatmentRecord.
	 * @return Collection<TreatmentRecord>
	 */
	public Collection<TreatmentRecord> getTreatmentRecord() {
		return treatmentRecord;
	}
	
	/**
	 * Method setTreatmentRecord.
	 * @param treatmentRecord Collection<TreatmentRecord>
	 */
	public void setTreatmentRecord(Collection<TreatmentRecord> treatmentRecord) {
		this.treatmentRecord = treatmentRecord;
	}
	
	/**
	 * Method getAppointments.
	 * @return Collection<Appointment>
	 */
	public Collection<Appointment> getAppointments() {
		return appointments;
	}
	
	/**
	 * Method setAppointments.
	 * @param appointments Collection<Appointment>
	 */
	public void setAppointments(Collection<Appointment> appointments) {
		this.appointments = appointments;
	}
	
	/**
	 * Method getTotalNumOfVisits.
	 * @return int
	 */
	public int getTotalNumOfVisits() {
		return totalNumOfVisits;
	}
	
	/**
	 * Method setTotalNumOfVisits.
	 * @param totalNumOfVisits int
	 */
	public void setTotalNumOfVisits(int totalNumOfVisits) {
		this.totalNumOfVisits = totalNumOfVisits;
	}
	
	/**
	 * Method getTotalPaymentinMonth.
	 * @return float
	 */
	public float getTotalPaymentinMonth() {
		return totalPaymentinMonth;
	}
	
	/**
	 * Method setTotalPaymentinMonth.
	 * @param totalPaymentinMonth float
	 */
	public void setTotalPaymentinMonth(float totalPaymentinMonth) {
		this.totalPaymentinMonth = totalPaymentinMonth;
	}
	
	/**
	 * Method getPatientID.
	 * @return int
	 */
	public int getPatientID(){
		return this.patientid;
	}
	
	/**
	 * Method setPatientID.
	 * @param patientid int
	 */
	public void setPatientID(int patientid){
		this.patientid = patientid;
	}
	
	/**
	 * Method addTreatmentRecord.
	 * @param tr TreatmentRecord
	 */
	public void addTreatmentRecord(TreatmentRecord tr){
		treatmentRecord.add(tr);
	}
	
	/**
	 * Method lookupPatients.
	 * @param firstName String
	 * @param lastName String
	 * @return Collection<Patient>
	 */
	public static List<Patient> lookupPatients(String firstName, String lastName){
		final List<Patient> patients = new ArrayList<Patient>();
		
		String sqlStatement = "SELECT users.*, p.*, pi.*, mi.* FROM users";

		sqlStatement = sqlStatement + " INNER JOIN patient AS p ON p.userid = users.id " +
				"INNER JOIN personalinfo AS pi ON p.id = pi.patientid " +
				"INNER JOIN medicalinfo AS mi ON p.id = mi.patientid";
		
		sqlStatement = sqlStatement + " WHERE usertype = 'p'";
		if(!firstName.equals("")){
			sqlStatement = sqlStatement + " AND firstname = \"" + firstName + "\"";
		}
		if(!lastName.equals("")){
			sqlStatement = sqlStatement + " AND lastname = \"" + lastName + "\"";
		}
		System.out.println(sqlStatement);
		try {
			final ResultSet rs = DBWrapper.query(sqlStatement);

			while(rs.next()){
				Collection<TreatmentRecord> records =
					TreatmentRecord.getTreatmentRecords(rs.getInt("users.id"));
				Collection<Appointment> appts = 
					Appointment.getAppointments(rs.getInt("users.id"));
				ResultSet allergyrs = DBWrapper.query("SELECT allergy " +
						"FROM allergies WHERE patientid = ?", rs.getInt("p.id"));
				Collection<String> allergies = new ArrayList<String>();
				while(allergyrs.next()){
					allergies.add(allergyrs.getString("allergy"));
				}
				
				MedicalInformation medinfo = new MedicalInformation(
						rs.getString("mi.pharmacy"),
						rs.getString("mi.insurancecarrier"),
						allergies.toArray(new String[0]));
				PersonalInformation persinfo = new PersonalInformation(
						rs.getString("pi.name"),
						rs.getString("pi.address"),
						rs.getString("pi.phone"),
						rs.getString("pi.email"),
						rs.getString("pi.gender").charAt(0),
						rs.getInt("pi.age"));
				PatientInformation patientinfo = 
					new PatientInformation(persinfo, medinfo);
				Patient toAdd = new Patient(rs.getString(
						"users.accessstring"), patientinfo, 
						rs.getString("users.username"),
						rs.getString("users.password"),
						rs.getString("users.firstname"),
						rs.getString("users.lastname"));
				patients.add(toAdd);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return patients;
	}
	
	/**
	 * Method lookupAllPatients.
	 * @return List<Patient>
	 */
	public static List<Patient> lookupAllPatients(){
		final List<Patient> patients = new ArrayList<Patient>();
		
		String sqlStatement = "SELECT * FROM users";

		sqlStatement = sqlStatement + " INNER JOIN patient AS p ON p.userid = users.id " +
				"INNER JOIN personalinfo AS pi ON p.id = pi.patientid " +
				"INNER JOIN medicalinfo AS mi ON p.id = mi.patientid";
		
		sqlStatement = sqlStatement + " WHERE usertype = 'p'";
		try {
			final ResultSet rs = DBWrapper.query(sqlStatement);

			while(rs.next()){
				Collection<TreatmentRecord> records = 
					TreatmentRecord.getTreatmentRecords(rs.getInt("users.id"));
				Collection<Appointment> appts = 
					Appointment.getAppointments(rs.getInt("users.id"));
				ResultSet allergyrs = DBWrapper.query(
						"SELECT allergy FROM allergies WHERE patientid = ?", 
						rs.getInt("mi.patientid"));
				Collection<String> allergies = new ArrayList<String>();
				while(allergyrs.next()){
					allergies.add(allergyrs.getString("allergy"));
				}
				
				MedicalInformation medinfo = new MedicalInformation(
						rs.getString("mi.pharmacy"),
						rs.getString("mi.insurancecarrier"),
						allergies.toArray(new String[0]));
				PersonalInformation persinfo = new PersonalInformation(
						rs.getString("pi.name"),
						rs.getString("pi.address"),
						rs.getString("pi.phone"),
						rs.getString("pi.email"),
						rs.getString("pi.gender").charAt(0),
						rs.getInt("pi.age"));
				PatientInformation patientinfo = 
					new PatientInformation(persinfo, medinfo);
				Patient toAdd = 
					new Patient(rs.getString("users.accessstring"), patientinfo, 
						rs.getString("users.username"),
						rs.getString("users.password"),
						rs.getString("users.firstname"),
						rs.getString("users.lastname"));
				toAdd.setPatientID(rs.getInt("p.id"));
				toAdd.setUID(rs.getInt("users.id"));
				patients.add(toAdd);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return patients;
	}
	
	/**
	 * Method createPatient.
	 */
	public void createPatient(){
		try {
			try {

				super.create();
				
				DBWrapper.execute("INSERT INTO " +
						"patient (userid, numvisits, amountPaid) VALUES (?,?,?)",
						this.getUID(),
						this.totalNumOfVisits,
						this.totalPaymentinMonth);
				
				final ResultSet rs = DBWrapper.query(
						"SELECT id FROM patient WHERE userid = ?", this.getUID());
				
				boolean empty = true;
				while(rs.next()){
					empty = false;
					this.patientid = rs.getInt("id");
					break;
				}
				if(empty){
					throw new Exception("Error getting patient ID from database.");
				}
				
				final PersonalInformation persinfo = 
					patientInformation.getPersonalInformation();
				final MedicalInformation medinfo = 
					patientInformation.getMedicalInformation();
				
				for(String allergy : medinfo.getAllergies()){
					DBWrapper.execute("INSERT INTO " +
							"allergies (patientid, allergy) VALUES (?,?)", 
							this.getPatientID(),
							allergy);
				}
				
				DBWrapper.execute("INSERT INTO medicalinfo " +
						"(patientid, pharmacy, insurancecarrier) VALUES (?,?,?)",
						this.getPatientID(),
						medinfo.getPharmacy(),
						medinfo.getInsuranceCarrier());
				
				DBWrapper.execute("INSERT INTO personalinfo " +
						"(patientid, name, address, phone, email, gender, age)" +
						" VALUES(?, ?, ?, ?, ?, ?, ?)", 
						this.getPatientID(),
						persinfo.getName(),
						persinfo.getAddress(),
						persinfo.getPhoneNumber(),
						persinfo.getEmailAddress(),
						persinfo.getGender(),
						persinfo.getAge());
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}catch(Exception e){
			e.printStackTrace();
		}
	}
//	public List<TreatmentRecord> getTreatmentRecords() throws SQLException // $codepro.audit.disable blankLineUsage
//	{
//		ResultSet rs = null;
//		List<TreatmentRecord> trs = new ArrayList<TreatmentRecord>();
//		rs = DBWrapper.query("Select * from treatmentrecords where patientid=?", patientid);
//		while(rs.next())
//		{
//			int bloodPressure = rs.getInt("bloodpressure");
//			int pulse = rs.getInt("pulse");
//			int temp = rs.getInt("temp");
//			int height = rs.getInt("height");
//			int weight = rs.getInt("weight");
//			Date date = rs.getDate("date");
//			VitalSigns signs = new VitalSigns(bloodPressure, pulse, temp, height, weight);
//			int doctor = rs.getInt("doctorid");
//			int nurse = rs.getInt("nurseid");
//			int doctorsOrders = rs.getInt("drsorders");
//			String diagnosis = rs.getString("diagnosis");
//			String symptoms = rs.getString("symptoms");
//			
//			trs.add(new TreatmentRecord(doctorsOrders, signs, doctor, nurse, patientid, date, diagnosis, symptoms));
//		}
//		return trs;
//	}
	/**
	 * Method updatePatient.
	 * @throws SQLException
	 */
	public void updatePatient() throws SQLException{
		super.update();
		
		DBWrapper.execute("update personalinfo set phone=?, " +
				"email=?, gender=?, age=? where patientid=?",
				patientInformation.getPersonalInformation().getPhoneNumber(),
				patientInformation.getPersonalInformation().getEmailAddress(),
				patientInformation.getPersonalInformation().getGender(),
				patientInformation.getPersonalInformation().getAge(),
				patientid);
		
		DBWrapper.execute("update medicalinfo set pharmacy=?, " +
				"insurancecarrier=? where patientid=? ",
				patientInformation.getMedicalInformation().getPharmacy(),
				patientInformation.getMedicalInformation().getInsuranceCarrier(),
				patientid);
	}
	
	/**
	 * Method deletePatient.
	 * @throws SQLException
	 */
	public void deletePatient() throws SQLException{
		super.destroy();
		
		DBWrapper.execute("delete from personalinfo where patientid = ?", patientid);
		DBWrapper.execute("delete from medicalinfo where patientId = ?", patientid);
		DBWrapper.execute("delete from patient where id = ?", patientid);
	}

	/**
	 * Method loadUserFromPatient.
	 * @param patientID int
	 * @return User
	 */
	public static User loadUserFromPatient(int patientID){
		User u = null; // $codepro.audit.disable
		
		String sqlStatement = "SELECT * FROM patient WHERE id = ?";
		try {
			final ResultSet rs = DBWrapper.query(sqlStatement, patientID);
			if(rs.next()){
				final int userID = rs.getInt("userid");
				
				sqlStatement = "SELECT * FROM users WHERE id = ?";
				final ResultSet rs2 = DBWrapper.query(sqlStatement, userID);
				if(rs2.next()){
					u = new User(rs2.getString("username"),
							rs2.getString("password"), rs2.getString("firstname"),
							rs2.getString("lastname"), rs2.getString("usertype"),
							rs2.getString("accessstring"));
				}
				
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return u;
		
	}

	/**
	 * Method loadPatientFromId.
	 * @param id int
	 * @return Patient
	 */
	public static Patient loadPatientFromId(int id){
		Patient patient = null;
		
		String sqlStatement = "SELECT * FROM users";

		sqlStatement = sqlStatement + " INNER JOIN patient AS p ON p.userid = users.id " +
				"INNER JOIN personalinfo AS pi ON p.id = pi.patientid " +
				"INNER JOIN medicalinfo AS mi ON p.id = mi.patientid";
		
		sqlStatement = sqlStatement + " WHERE usertype = 'p' and p.id=?";
		try {
			final ResultSet rs = DBWrapper.query(sqlStatement, id);

			if(rs.next()){
				final Collection<TreatmentRecord> records = 
					TreatmentRecord.getTreatmentRecords(rs.getInt("users.id"));
				final Collection<Appointment> appts = 
					Appointment.getAppointments(rs.getInt("users.id"));
				
				final ResultSet allergyrs = DBWrapper.query(
						"SELECT allergy FROM allergies WHERE patientid = ?", 
						rs.getInt("mi.patientid"));
				final Collection<String> allergies = new ArrayList<String>();
				while(allergyrs.next()){
					allergies.add(allergyrs.getString("allergy"));
				}
				
				final MedicalInformation medinfo = new MedicalInformation(
						rs.getString("mi.pharmacy"),
						rs.getString("mi.insurancecarrier"),
						allergies.toArray(new String[0]));
				final PersonalInformation persinfo = new PersonalInformation(
						rs.getString("pi.name"),
						rs.getString("pi.address"),
						rs.getString("pi.phone"),
						rs.getString("pi.email"),
						rs.getString("pi.gender").charAt(0),
						rs.getInt("pi.age"));
				final PatientInformation patientinfo = 
					new PatientInformation(persinfo, medinfo);
				final Patient toAdd = new Patient(
						rs.getString("users.accessstring"), patientinfo, 
						rs.getString("users.username"),
						rs.getString("users.password"),
						rs.getString("users.firstname"),
						rs.getString("users.lastname"));
				toAdd.setPatientID(rs.getInt("p.id"));
				toAdd.setUID(rs.getInt("users.id"));
				patient = toAdd;
				
				toAdd.setTreatmentRecord(records);
				toAdd.setAppointments(appts);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return patient;
	}
	
	/**
	 * This method creates a new patient with blank fields except
	 * for the patient's first and last name and e-mail address.
	 * @param first
	 * @param last
	 * @param email
	 * @return Patient
	 */
	public static Patient createBlankPatient(String first, String last, String email) {

		final PersonalInformation personalInformation = 
			new PersonalInformation(first, last, "", "", 'm', new Integer(0));
		final MedicalInformation medicalInformation = 
			new MedicalInformation("", "", new String[]{""});
		final PatientInformation patientInformation = 
			new PatientInformation(personalInformation, medicalInformation);
		final Patient newPatient = new Patient(Patient.PATIENTDEFPERMS,
				patientInformation, first + last, email, first, last);
		
		return newPatient;

	}
	
	/**
	 * Method toString.
	 * @return String
	 */
	@Override
	public String toString(){
		return firstName + " " +  lastName;
	}
}
